﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataAccess = Microsoft.MSE.Catalog.Module.Data;
using DTO = Microsoft.MSE.Catalog.Contracts;
using System.Xml;
using System.Data.SqlClient;
using System.Data;
using System.Xml.Schema;
using System.IO;

namespace Microsoft.MSE.Catalog.Module.Business
{
    public class OperationManager
    {
        public OperationManager()
        {

        }

        #region Operation functions

        public static Guid CreateOperation(DTO.Operation operation)
        {
            Guid ID;
            Guid policyID = Guid.Empty;
            Guid implementationID = Guid.Empty;

            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);

                Guid opID = DataAccess.Entity.GetIDFromName(operation.Name, Microsoft.MSE.Catalog.Contracts.EntityClass.Operation, txn, conn);
                if (opID == Guid.Empty || (opID.CompareTo(operation.ID) == 0))
                {
                    try
                    {

                        if (operation.Policy != null)
                        {
                            if ((operation.Policy.ID == null) || (!DataAccess.Entity.EntityExists(operation.Policy.ID, DTO.EntityClass.Policy, txn, conn)))
                            {
                                policyID = PolicyManager.CreatePolicy(operation.Policy, txn, conn);
                            }
                            else
                            {
                                policyID = operation.Policy.ID;
                            }
                        }

                        //Calling the data access layer
                        ID = DataAccess.Operation.CreateOperation(operation, txn, conn);
                        
                        if (operation.Versions != null)
                        {
                            foreach (DTO.OperationVersion version in operation.Versions)
                            {
                                version.OperationID = operation.ID;
                                OperationManager.CreateOperationVersion(version, txn, conn);
                            }
                        }


                        if (txn != null) txn.Commit(); //Commit transaction
                    }
                    catch (Exception)
                    {
                        if (txn != null) txn.Rollback(); //Rollback transaction
                        throw;
                    }
                }
                else
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw new ApplicationException("Operation already exists in the Service Model");
                }
            } //Connection is disposed here

            return ID;
        }

        public static DTO.Operation UpdateOperation(DTO.Operation operation)
        {
            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);

                Guid opID = DataAccess.Entity.GetIDFromName(operation.Name, Microsoft.MSE.Catalog.Contracts.EntityClass.Operation, txn, conn);
                if (opID == Guid.Empty || (opID.CompareTo(operation.ID) == 0))
                {

                    try
                    {

                        //Change Tracking
                        DTO.DBEventContext eventContext = ChangeTrackingHelper.GetEventContextForOperationUpdate(operation.ID, txn, conn);

                        //Calling the data access layer
                        operation = DataAccess.Operation.UpdateOperation(operation, txn, conn);

                        //get existing versions

                        DTO.OperationVersionList list = OperationManager.ListOperationVersions(operation.ID, txn, conn);

                        //Note: there is no need to track changes at the op version level
                        //this method will raise the event at operation level which is coarser grained
                        if (list.OperationVersions != null)
                        {
                            bool present = false;
                            if (list.OperationVersions.Count > operation.Versions.Count)
                            {
                                foreach (DTO.OperationVersionListElement version in list.OperationVersions)
                                {
                                    present = false;
                                    foreach (DTO.OperationVersion xversion in operation.Versions)
                                    {
                                        if (version.ID == xversion.ID)
                                            present = true;
                                    }
                                    if (!present)
                                        DeleteOperationVersion(version.ID, false, txn, conn);


                                }
                            }
                            foreach (DTO.OperationVersion xversion in operation.Versions)
                            {
                                present = false;
                                foreach (DTO.OperationVersionListElement version in list.OperationVersions)
                                {
                                    if (version.ID == xversion.ID)
                                    {
                                        //no need to track changes at the version level since we will raise the event at operation level
                                        UpdateOperationVersion(xversion, false, txn, conn);
                                        present = true;
                                        break;
                                    }
                                }
                                if (!present)
                                    CreateOperationVersion(xversion, txn, conn);
                            }

                        }

                        //save change tracking data
                        DataAccess.RepositoryChange.Save(eventContext, txn, conn);

                        if (txn != null) txn.Commit(); //Commit transaction
                    }
                    catch (Exception)
                    {
                        if (txn != null) txn.Rollback(); //Rollback transaction
                        throw;
                    }
                }
                else
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw new ApplicationException("Operation already exists in the Service Model");
                }
            } //Connection is disposed here

            return operation;
        }

        public static void DeleteOperation(Guid ID)
        {
            //Calling the data access layer
            DataAccess.Operation.DeleteOperation(ID, null, null);
        }

        public static DTO.Operation GetOperation(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            //Calling the data access layer            
            DTO.Operation operation = DataAccess.Operation.GetOperation(ID, txn, conn);

            //Get Operation version
            DTO.OperationVersionList list = OperationManager.ListOperationVersions(ID, txn, conn);

            if (list.OperationVersions != null)
            {
                operation.Versions = new List<DTO.OperationVersion>();
                foreach (DTO.OperationVersionListElement version in list.OperationVersions)
                {
                    operation.Versions.Add(OperationManager.GetOperationVersion(version.ID, txn, conn));
                }
            }
            operation.EndpointList = EndpointManager.ListAssociatedEndpointsForOperation(ID, txn, conn);

            return operation;
        }

        public static List<DTO.OperationVersion> LoadAllOperationVersions(DTO.OperationVersionList publishedOpVers, SqlTransaction txn, SqlConnection conn)
        {
            List<DTO.OperationVersion> operationVersions = new List<DTO.OperationVersion>();
            foreach (DTO.OperationVersionListElement ovle in publishedOpVers.OperationVersions)
            {
                operationVersions.Add(OperationManager.GetOperationVersion(ovle.ID, txn, conn));
            }
            return operationVersions;
        }

        public static DTO.OperationList ListOperations(SqlTransaction txn, SqlConnection conn)
        {
            //Calling the data access layer
            return DataAccess.Operation.ListOperations(txn, conn);
        }

        public static DTO.OperationList ListOperationsByElement(Guid SchemaID, string elementName, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.Operation.ListOperationsByElement(SchemaID, elementName, txn, conn);
        }

        public static DTO.OperationList ListOperationsBySchema(Guid SchemaID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.Operation.ListOperationsBySchema(SchemaID, txn, conn);
        }

        public static DTO.OperationList ListOperationsByResource(Guid ResourceID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.Operation.ListOperationsByResource(ResourceID, txn, conn);
        }

        public static DTO.OperationList ListOperationsByFirstElement(Guid SchemaID, string elementName, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.Operation.ListOperationsByFirstElement(SchemaID, elementName, txn, conn);
        }

        #endregion

        #region Operation Version functions

        public static Guid CreateOperationVersion(DTO.OperationVersion version, SqlTransaction txn, SqlConnection conn)
        {
            //This function always need a connection and a transaction
            //If no conn and txn then create it
            //If conn and txn exists then use it
            
            Guid ID;
            bool autoclose = false;
            bool newTransaction = false;
            Guid implementationID = Guid.Empty;

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                if (txn == null)
                {
                    txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);
                    newTransaction = true;
                }

                
                //Create operation version
                ID = DataAccess.OperationVersion.CreateOperationVersion(version, txn, conn);

                int partNo = 0;

                if (version.RequestMsg != null)
                {
                    foreach (DTO.MessagePart part in version.RequestMsg)
                    {
                        DataAccess.MessagePart.CreateMessagePart(part, ID, partNo++, SC.IsRequestMsg, txn, conn);
                    }
                }

                if (version.ResponseMsg != null)
                {
                    partNo = 0;
                    foreach (DTO.MessagePart part in version.ResponseMsg)
                    {
                        DataAccess.MessagePart.CreateMessagePart(part, ID, partNo++, SC.IsResponseMsg, txn, conn);
                    }
                }
                // Create Soap Faults
                if (version.SoapFaults != null && version.SoapFaults.Count > 0)
                {
                    partNo = 0;
                    foreach (DTO.SoapFault fault in version.SoapFaults)
                    {
                        DataAccess.SoapFault.CreateSoapFault(fault, ID, txn, conn);
                    }
                }

                // Create Message Headers
                int headerNo = 0;

                if (version.RequestHeaders != null)
                {
                    foreach (DTO.MessageHeader header in version.RequestHeaders)
                    {
                        DataAccess.MessageHeader.CreateMessageHeader(header, ID, headerNo++, true, txn, conn);
                    }
                }

                if (version.ResponseHeaders != null)
                {
                    headerNo = 0;
                    foreach (DTO.MessageHeader header in version.ResponseHeaders)
                    {
                        DataAccess.MessageHeader.CreateMessageHeader(header, ID, headerNo++, false, txn, conn);
                    }
                }
                if ((autoclose) && (txn != null) && (newTransaction)) txn.Commit();
            }
            catch (Exception)
            {
                if ((txn != null) && (newTransaction))  txn.Rollback(); 
                throw;
            }
            finally
            {
                if (autoclose && (conn !=null))  conn.Close(); 
            }

            return ID;
        }

        public static void DeleteOperationVersion(Guid ID, bool trackChanges, SqlTransaction txn, SqlConnection conn)
        {
            //TODO candidate for transaction??

            //Change Tracking
            DTO.DBEventContext eventContext = null;
            if (trackChanges)
            {
                eventContext = ChangeTrackingHelper.GetEventContextForOperationVersionDelete(ID, txn, conn);
            }

            DataAccess.OperationVersion.DeleteOperationVersion(ID, txn, conn);

            // Delete all Soap Faults associations for this version
            DataAccess.SoapFault.DeleteSoapFaults(ID, txn, conn);

            //send notification to affected runtimes
            if (trackChanges)
            {
                DataAccess.RepositoryChange.Save(eventContext, txn, conn);
            }
        }

        public static DTO.OperationVersion GetOperationVersion(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.OperationVersion.GetOperationVersion(ID, txn, conn);
        }

        public static List<DTO.OperationVersion> GetOperationVersionsForEndpointAndAction(Guid endpointID, string action, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.OperationVersion.GetOperationVersionsForEndpointAndAction(endpointID, action, txn, conn);
        }

        public static List<DTO.OperationVersion> GetOperationVersionsForEndpointAndFirstBodyElement(Guid endpointID, string elementName, string namespaceURI, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.OperationVersion.GetOperationVersionsForEndpointAndFirstBodyElement(endpointID, elementName, namespaceURI, txn, conn);
        }

        public static DTO.OperationVersionList ListOperationVersions(Guid ID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.OperationVersion.ListOperationVersions(ID, txn, conn);
        }

        public static DTO.OperationVersionList ListOperationVersionsBySchema(Guid SchemaID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.OperationVersion.ListOperationVersionsBySchema(SchemaID, txn, conn);
        }

        public static DTO.OperationVersionList ListOperationVersionsForResource(Guid ResourceID, SqlTransaction txn, SqlConnection conn)
        {
            return DataAccess.OperationVersion.ListOperationVersionsForResource(ResourceID, txn, conn);
        }

        public static DTO.OperationVersion UpdateOperationVersion(DTO.OperationVersion operationVersion, bool trackChanges,SqlTransaction txn, SqlConnection conn)
        {
            //This function always need a connection and a transaction
            //If no conn and txn then create then close and commit/rollback here
            //If conn and txn exists then use it. Do not close and commit/rollback here
            
            bool autoclose = false;
            bool newTransaction = false;
            Guid policyID = Guid.Empty;
            Guid implementationID = Guid.Empty;

            try
            {
                if (conn == null) conn = CatalogSvcHelper.GetConnection();
                if (conn.State == ConnectionState.Closed)
                {
                    autoclose = true;
                    conn.Open();
                }

                if (txn == null)
                {
                    txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);
                    newTransaction = true;
                }            

                //Change Tracking
                DTO.DBEventContext eventContext = null;
                if (trackChanges)
                {
                    eventContext = ChangeTrackingHelper.GetEventContextForOperationVersionUpdate(operationVersion.ID, txn, conn);
                }

                operationVersion = DataAccess.OperationVersion.UpdateOperationVersion(operationVersion, txn, conn);

                int partNo = 0;

                DataAccess.MessagePart.DeleteMessagesFromOperationVersion(operationVersion.ID, txn, conn);

                if (operationVersion.RequestMsg != null)
                {
                    foreach (DTO.MessagePart part in operationVersion.RequestMsg)
                    {
                        DataAccess.MessagePart.CreateMessagePart(part, operationVersion.ID, partNo++, SC.IsRequestMsg, txn, conn);
                    }
                }

                if (operationVersion.ResponseMsg != null)
                {
                    partNo = 0;
                    foreach (DTO.MessagePart part in operationVersion.ResponseMsg)
                    {
                        DataAccess.MessagePart.CreateMessagePart(part, operationVersion.ID, partNo++, SC.IsResponseMsg, txn, conn);
                    }
                }

                if (operationVersion.SoapFaults != null)
                {
                    DataAccess.SoapFault.DeleteSoapFaults(operationVersion.ID, txn, conn);
                    foreach (DTO.SoapFault fault in operationVersion.SoapFaults)
                    {
                        DataAccess.SoapFault.CreateSoapFault(fault,operationVersion.ID, txn, conn);
                    }
                }

                if (operationVersion.RequestHeaders != null || operationVersion.ResponseHeaders != null )
                {
                    DataAccess.MessageHeader.DeleteMessageHeaders(operationVersion.ID, txn, conn);
                    if (operationVersion.RequestHeaders != null)
                    {
                        for (int counter = 0; counter < operationVersion.RequestHeaders.Count; counter++)
                        {
                            DataAccess.MessageHeader.CreateMessageHeader(operationVersion.RequestHeaders[counter], operationVersion.ID, counter, true, txn, conn);
                        }
                    }
                    if (operationVersion.ResponseHeaders != null)
                    {
                        for (int counter = 0; counter < operationVersion.ResponseHeaders.Count; counter++)
                        {
                            DataAccess.MessageHeader.CreateMessageHeader(operationVersion.ResponseHeaders[counter], operationVersion.ID, counter, false, txn, conn);
                        }
                    }
                }

                //save change tracking data
                if (trackChanges)
                {
                    DataAccess.RepositoryChange.Save(eventContext, txn, conn);
                }

                if ((autoclose) && (txn != null) && (newTransaction)) txn.Commit();
            }
            catch (Exception)
            {
                if ((txn != null) && (newTransaction)) txn.Rollback();
                throw;
            }
            finally
            {
                if (autoclose && (conn != null)) conn.Close();
            }

            return operationVersion;
        }

        public static void RemoveAssociatedOperationVersionFromEndpoint(Guid operationVersionID, Guid endpointID, SqlTransaction txn, SqlConnection conn)
        {
            //Change Tracking
            DTO.DBEventContext eventContext = ChangeTrackingHelper.GetEventContextForOperationAssociationRemove(endpointID, operationVersionID, txn, conn);

            DataAccess.OperationVersion.RemoveAssociatedOperationVersionFromEndpoint(operationVersionID, endpointID, txn, conn);

            //save change tracking data
            DataAccess.RepositoryChange.Save(eventContext, txn, conn);

        }

        public static void RemovePublishedOperationVersionFromEndpoint(Guid operationVersionID, Guid endpointID, SqlTransaction txn, SqlConnection conn)
        {

            //TODO Do we need a transaction here?

            //Change Tracking
            DTO.DBEventContext eventContext = ChangeTrackingHelper.GetEventContextForEndpointUnPublishOperation(endpointID, operationVersionID, txn, conn);

            DataAccess.OperationVersion.RemovePublishedOperationVersionFromEndpoint(operationVersionID, endpointID, txn, conn);

            DTO.OperationVersionList pubOpVersionsList = EndpointManager.ListPublishedOperationsForEndpoint(endpointID, txn, conn);
            if (pubOpVersionsList == null ||
                pubOpVersionsList.OperationVersions == null ||
                pubOpVersionsList.OperationVersions.Count == 0)
            {
                if (eventContext != null && eventContext.EventData != null)
                {
                    // Remove any UDDI associations 
                    eventContext.EventData.ForEach(item => { EndpointManager.RemoveEndPointFromUddi(endpointID, item.RuntimeServerId, txn, conn); });
                }
            }

            //save change tracking data
            DataAccess.RepositoryChange.Save(eventContext, txn, conn);

        }

        public static Boolean ValidateOperationVersionRequest(XmlElement request, Guid opVersionID, SqlTransaction txn, SqlConnection conn)
        {
            XmlDocument tempXMLDoc = new XmlDocument();
            XmlSchemaSet schemaSet = new XmlSchemaSet();
            XmlReaderSettings settings = new XmlReaderSettings();

            XmlDocument mpSchema = new XmlDocument();
            Dictionary<string, string> schemaHash = new Dictionary<string, string>();

            tempXMLDoc.LoadXml(request.OuterXml);

            DTO.OperationVersion opVer = GetOperationVersion(opVersionID, txn, conn);

            // Before we do any validation, we may want to check if 
            // the request's document element name is the same as specified in request messsage part
            // Will have to modify for multipart message
            if (opVer.RequestMsg != null && opVer.RequestMsg.Count > 0)
            {
                if (string.Compare(request.LocalName, opVer.RequestMsg[0].SchemaObject.Name, false) != 0)
                {
                    Console.WriteLine("Request's DocumentElement name [{0}] is different from Request's Message Part Element Name [{1}]", request.LocalName, opVer.RequestMsg[0].SchemaObject.Name);
                    return false;
                }
            }
            else
            {
                Console.WriteLine("Request's Message Part for Version [{0}] does not exist", opVer.Version.ToString());
                return false;
            }

            try
            {
                schemaSet = SchemaManager.ExtractSchemaSetFromRelevantSchemaTypes(opVer.RequestMsg,txn, conn);
            }
            catch (Exception ex)
            {
                //return false;
                throw new ApplicationException("Failed to validate Request Message Schema due to error [" + ex.Message + "]");
            }

            try
            {
                settings.Schemas = schemaSet;
                settings.ConformanceLevel = ConformanceLevel.Auto;
                settings.ValidationType = ValidationType.Schema;
                settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
                settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;

                bool hasError = false;
                // Warning validation only works if we have an event handler
                settings.ValidationEventHandler += delegate(object sender, ValidationEventArgs e)
                {
                    Console.WriteLine("Validation Error:[{0}]", CatalogSvcHelper.GetExceptionDetails(e.Exception));
                    hasError = true;
                };

                // Create the XmlReader object.
                XmlReader reader = XmlReader.Create(new StringReader(tempXMLDoc.OuterXml), settings);

                // Parse the document. An XMLException should be thrown if there is an validation error
                while (reader.Read())
                {
                    if (hasError == true)
                        break;
                    Console.WriteLine(reader.Name + reader.NamespaceURI);
                }
                // This will only return true if there is no error
                return (hasError == false);
            }

            catch (Exception ex)
            {
                //return false;
                throw new ApplicationException("Failed to validate Request Message due to error [" + ex.Message + "]");
            }
        }

        public static void AssignPublishedOperationVersionToEndpoint(Guid operationVersionID, Guid endpointID, SqlTransaction txn, SqlConnection conn)
        {
            //TODO Candidate for transaction ??

            //Change Tracking
            DTO.DBEventContext eventContext = ChangeTrackingHelper.GetEventContextForEndpointPublishOperation(endpointID, operationVersionID, txn, conn);

            DataAccess.OperationVersion.AssignPublishedOperationVersionToEndpoint(operationVersionID, endpointID, txn, conn);

            // Validate WSDL's Schema content
            DTO.Endpoint endpoint = EndpointManager.GetEndpoint(endpointID,Guid.Empty,false,txn,conn);

            bool validateWSDLSchemaContent = EndpointManager.ValidateEndPointWSDLSchemaContent(endpoint, txn, conn);

            // If schema content is not valid then remove the operation version and throw an exception
            if (validateWSDLSchemaContent == false)
            {
                DataAccess.OperationVersion.RemovePublishedOperationVersionFromEndpoint(operationVersionID, endpointID, txn, conn);
                throw new ApplicationException(string.Format("Failed to publish OperationVersion[ID={0}] to the Endpoint[{1}] as the WSDL schema content validation failed",operationVersionID,endpoint.Name)); 
            }

            // Update any UDDI associations 
            if (eventContext != null && eventContext.EventData != null)
            {                
                eventContext.EventData.ForEach(item => { EndpointManager.PublishEndPointToUddi(endpointID, item.RuntimeServerId, false, txn, conn); });
            }

            //save change tracking data
            DataAccess.RepositoryChange.Save(eventContext, txn, conn);

        }

        public static void AssignAssociatedOperationVersionToEndpoint(Guid operationVersionID, Guid endpointID, SqlTransaction txn, SqlConnection conn)
        {
            //Change Tracking
            DTO.DBEventContext eventContext = ChangeTrackingHelper.GetEventContextForOperationAssociationAdded(endpointID, operationVersionID, txn, conn);

            DataAccess.OperationVersion.AssignAssociatedOperationVersionToEndpoint(operationVersionID, endpointID, txn, conn);

            //save change tracking data
            DataAccess.RepositoryChange.Save(eventContext, txn, conn);
        }
        public static void UpdateOperationVersionSchemaObjectReferences(Guid operationVersionID, 
                                                                        DTO.SchemaObject oldSchemaObject, DTO.SchemaObject newSchemaObject,
                                                                        SqlTransaction txn, SqlConnection conn)
        {
            DTO.OperationVersion opVersion = GetOperationVersion(operationVersionID, txn, conn);
            if (opVersion.RequestMsg != null)
            {
                foreach (DTO.MessagePart messagePart in opVersion.RequestMsg)
                {
                    if (messagePart.SchemaObject.ID == oldSchemaObject.ID)
                    {
                        messagePart.SchemaObject = newSchemaObject;
                    }
                }
            }
            if (opVersion.ResponseMsg != null)
            {
                foreach (DTO.MessagePart messagePart in opVersion.ResponseMsg)
                {
                    if (messagePart.SchemaObject.ID == oldSchemaObject.ID)
                    {
                        messagePart.SchemaObject = newSchemaObject;
                    }
                }
            }
            if (opVersion.SoapFaults != null)
            {
                foreach (DTO.SoapFault fault in opVersion.SoapFaults)
                {
                    if (fault.SchemaObject.ID == oldSchemaObject.ID)
                    {
                        fault.SchemaObject = newSchemaObject;
                    }
                }
            }
            if (opVersion.RequestHeaders != null)
            {
                foreach (DTO.MessageHeader header in opVersion.RequestHeaders)
                {
                    if (header.SchemaObject.ID == oldSchemaObject.ID)
                    {
                        header.SchemaObject = newSchemaObject;
                    }
                }
            }
            if (opVersion.ResponseHeaders != null)
            {
                foreach (DTO.MessageHeader header in opVersion.ResponseHeaders)
                {
                    if (header.SchemaObject.ID == oldSchemaObject.ID)
                    {
                        header.SchemaObject = newSchemaObject;
                    }
                }
            }
            UpdateOperationVersion(opVersion,true,txn,conn);
        }

        public static void UpdateResourceSchemaObjectReferences(Guid resourceID, DTO.SchemaObject oldSchemaObject, DTO.SchemaObject newSchemaObject
                                                , SqlTransaction txn, SqlConnection conn)
        {
            DTO.Resource resource = DataAccess.Resource.GetResource(resourceID, false, null, txn, conn);
            if (resource.RequestSchemaObject != null && resource.RequestSchemaObject.ID == oldSchemaObject.ID)
            {
                resource.RequestSchemaObject = newSchemaObject;
            }
            if (resource.ResponseSchemaObject != null && resource.ResponseSchemaObject.ID == oldSchemaObject.ID)
            {
                resource.ResponseSchemaObject = newSchemaObject;
            }
            DataAccess.Resource.UpdateResource(resource, txn, conn);
        }


        #endregion

        #region Operations Group functions

        public static List<DTO.OperationListElement> ListOperationsByGroup(Guid entityGroupID)
        {
            return DataAccess.Operation.ListOperationsByGroup(entityGroupID, null, null);
        }

        public static DTO.OperationGroup CreateOperationGroup(DTO.OperationGroup operationGroup)
        {
            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);

                try
                {
                    operationGroup.ID = DataAccess.Entity.CreateEntityGroup(operationGroup.Name, operationGroup.Description, 4, txn, conn);

                    if (operationGroup.Operations != null)
                    {
                        foreach (DTO.OperationListElement operation in operationGroup.Operations)
                        {
                            DataAccess.Entity.AssignEntityToEntityGroup(operationGroup.ID, operation.ID, txn, conn);
                        }
                    }

                    if (txn != null) txn.Commit(); //Commit transaction
                }
                catch (Exception)
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw;
                }
            } //Connection is disposed here

            return operationGroup;
        }

        public static DTO.OperationGroup UpdateOperationGroup(DTO.OperationGroup operationGroup)
        {
            using (SqlConnection conn = CatalogSvcHelper.GetConnection())
            {
                conn.Open();
                SqlTransaction txn = CatalogSvcHelper.GetTransaction(conn, IsolationLevel.Snapshot);

                try
                {

                    DataAccess.Entity.UpdateEntityGroup(operationGroup.ID, operationGroup.Name, operationGroup.Description, txn, conn);


                    List<DTO.OperationListElement> oldList = DataAccess.Operation.ListOperationsByGroup(operationGroup.ID, txn, conn);
                    /// Delete all items from the old list
                    if (oldList != null)
                    {
                        foreach (DTO.OperationListElement oldListElement in oldList)
                        {
                            DataAccess.Entity.RemoveEntityFromEntityGroup(operationGroup.ID, oldListElement.ID, txn, conn);
                        }
                    }
                    /// Add all items from the new list
                    if (operationGroup.Operations != null)
                    {
                        foreach (DTO.OperationListElement newListElement in operationGroup.Operations)
                        {
                            DataAccess.Entity.AssignEntityToEntityGroup(operationGroup.ID, newListElement.ID, txn, conn);
                        }
                    }

                    if (txn != null) txn.Commit(); //Commit transaction
                }
                catch (Exception)
                {
                    if (txn != null) txn.Rollback(); //Rollback transaction
                    throw;
                }
            } //Connection is disposed here

            return operationGroup;
        }

        public static DTO.EntityGroupList ListOperationGroupsByOperation(Guid entityID)
        {
            return DataAccess.Operation.ListOperationGroupsByOperation(entityID, null, null);
        }

        public static DTO.EntityGroupList ListOperationGroups()
        {
            return DataAccess.Operation.ListOperationGroups( null, null);
        }

        public static DTO.OperationGroup GetOperationGroup(Guid ID)
        {
            DTO.OperationGroup operationGroup = new DTO.OperationGroup();
            DTO.EntityGroup entityGroup = new DTO.EntityGroup();

            entityGroup = DataAccess.Entity.GetEntityGroup(ID, null, null);

            operationGroup.ID = entityGroup.ID;
            operationGroup.Name = entityGroup.Name;
            operationGroup.Description = entityGroup.Description;

            operationGroup.Operations = ListOperationsByGroup(ID);

            return operationGroup;
        }

        #endregion
    }
}
